package com.michael.demos.base.thread.juc;

import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 类功能描述:
 * <pre>
 *   倒计数器使用 DEMO  底层由AQS实现
 *   主要用来协调多个线程之间的同步，起到一个同步器的作用
 *   可以部分替代 Thread.join()方法
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/8/12 10:28
 */
public class CountDownLatchDemo {

	/** 模拟老师讲课的场景 */
	public static void lecture() throws InterruptedException {
		// 学生数量
		int countStu = 10;
		// 空余座位
		CountDownLatch freeSeat = new CountDownLatch(countStu);
		System.out.println("上课铃声响起...老师准备讲课");
		for (int i = 0; i < countStu; i++) {
			new StuThread(freeSeat, "学生 " + i + " ").start();
		}

		// 所有学生在座位坐好了再讲课
		freeSeat.await();
		System.out.println("所有同学都坐好了，老师开始讲课");

//		freeSeat.await(3, TimeUnit.SECONDS);
//		System.out.println("上课时间到，老师开始讲课");
	}

	/** 模拟按流程办事 - 建房子 */
	public static void doWork() throws InterruptedException {

		WorkThread worker0 = new WorkThread("[基础架构团队]");
		WorkThread worker1 = new WorkThread("[搬砖团队]");
		WorkThread worker2 = new WorkThread("[封顶团队]");
		WorkThread worker3 = new WorkThread("[装修团队]");

		worker0.setNextWroks(worker1);
		worker1.setNextWroks(worker2);
		worker2.setNextWroks(worker3);

		worker0.start();
		worker1.start();
		worker2.start();
		worker3.start();

		// 工程开始
		System.out.println();
		System.out.println("开始建房子...");
		worker0.countDown();
	}

	public static void main(String[] args) throws InterruptedException {
		lecture();
		doWork();
	}
}

class WorkThread extends Thread {

	private CountDownLatch latch;
	// 后置任务
	private WorkThread nextWroks;

	public WorkThread(String threadName) {
		setName(threadName);
		this.latch = new CountDownLatch(1);
	}

	public void setNextWroks(WorkThread nextWroks) {
		this.nextWroks = nextWroks;
	}

	private int getRandomInt(int min, int max) {
		Random random = new Random();
		return min + random.nextInt((max - min) + 1);
	}

	public void countDown() {
		latch.countDown();
	}

	@Override
	public void run() {

		String name = Thread.currentThread().getName();

		try {
			// 等待前置工作完成后再进行
			latch.await();
			int randomInt = getRandomInt(500, 2000);
			System.out.println(name + " 开始干活，需要时间：" + randomInt);
			TimeUnit.MILLISECONDS.sleep(randomInt);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			System.out.println(name + " 完成工作");
			if (nextWroks != null) {
				nextWroks.countDown();
			} else {
				System.out.println("所有工作均已完成");
			}
		}
	}
}

class StuThread extends Thread {

	private final CountDownLatch freeSeat;

	public StuThread(CountDownLatch freeSeat, String threadName) {
		this.freeSeat = freeSeat;
		setName(threadName);
	}

	private int getRandomInt(int min, int max) {
		Random random = new Random();
		return min + random.nextInt((max - min) + 1);
	}

	@Override
	public void run() {

		String name = Thread.currentThread().getName();
		try {
			int randomInt = getRandomInt(1000, 5000);
//			System.out.println(name + "到达教室需要时间：" + randomInt);
			TimeUnit.MILLISECONDS.sleep(randomInt);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			System.out.println(name + "在座位上坐好");
			freeSeat.countDown();
			System.out.println(name + Arrays.asList("正在玩手机", "正在看书", "正在玩笔").get(getRandomInt(0, 2)));
		}
	}
}
